# -*- coding: utf-8 -*-
from openerp.osv  import  osv, fields
import openerp.addons.decimal_precision as dp

class sale_order(osv.osv):
    _name = 'sale.order'
    _inherit = ['mail.thread', 'ir.needaction_mixin']
    _description = u"销售订单"

    def _invoiced_rate(self,cursor,user,ids,name,arg,context=None):
        res = {}
        for sale in self.browse(cursor,user,ids,context=context):
            if sale.invoiced:
                res[sale.id] = 100.0
                continue
            tot = 0.0
            for invoice in sale.invoice_ids:
                if invoice.state not in ('draft','cancel'):
                    tot += invoice.amount_untaxed
            if tot:
                res[sale.id] = min(100.0,tot*100.0/(sale.amount_untaxed or 1.00))
            else:
                res[sale.id] = 0.0
        return res

    def _invoiced(self,cursor,user,ids,name,arg,context=None):
        res = {}
        for sale in self.browse(cursor,user,ids,context=context):
            res[sale.id] = True
            invoice_existence = False
            for invoice in sale.invoice_ids:
                if invoice.state != 'cancel':
                    invoice_existence =True
                    if invoice.state != 'paid':
                        res[sale.id] = False
                        break
            if not invoice_existence or sale.state=='manual':
                res[sale.id] = False
        return res

    def _invoiced_search(self,cursor,user,obj,name,args,context=None):
        if not len(args):
            return []
        clause = ''
        sale_clause = ''
        no_invoiced = False
        for arg in args:
            if (arg[1]=='=' and arg[2] or (arg[1]=='!=' and not arg[2])): #invoiced=True订单所有发票已支付
                clause += 'AND inv.state=\'paid\''
            else:
                clause += 'AND inv.state != \'paid\' AND sale.state != \'cancel\' AND inv.state <> \'paid\' AND rel.order_id = sale.id'
                sale_clause = ', sale_order AS sale'
                no_invoiced = True
                
        cursor.execute('SELECT rel.order_id' \
                        'FROM sale_order_invoice_rel AS rel , account_invoice AS inv' + sale_clause + \
                        'WHERE rel.invoice_id = inv.id' + clause)
        res = cursor.fetchall()
        if no_invoiced :
            cursor.execute('SELECT sale.id' \
                           'FROM sale_order AS sale' \
                           'WHERE sale.id NOT IN' \
                                '(SELECT rel.order_id' \
                                'FROM sale_order_invoice_rel AS rel ) and sale.state != \'cancel\'' )
            res.extend(cursor.fetchall())
        if not res:
            return [('id','=',0)]
        return [('id','in',[x[0] for x in res])]

    def _invoice_exists(self,cursor,user,ids,name,arg,context=None):
        res = {}
        for sale in self.browse(cursor,user,ids,context=context):
            res[sale.id] = False
            if sale.invoice_ids:
                res[sale.id] = True
        return res

    def _amount_all_wrapper(self, cr, uid, ids, field_name, arg, context=None):
        """ 包装一下，以便避免被调用的参数直接使用function函数传递过来的参数"""
        return self._amount_all(cr, uid, ids, field_name, arg, context=context)
    
    def _amount_all(self, cr, uid, ids, field_name, arg, context=None):
        cur_obj = self.pool.get('res.currency')
        res = {}
        for order in self.browse(cr, uid, ids, context=context):
            res[order.id] = {
                'amount_untaxed':0.0,
                'amount_tax':0.0,
                'amount_total':0.0,
                }
            val = val1 = 0.0
            cur = order.pricelist_id.currency_id 
            for line in order.order_line:
                val1 += line.price_subtotal
                val += self._amount_line_tax(cr, uid, line, context=context)
            res[order.id]['amount_tax'] = cur_obj.round(cr,uid,cur,val)
            res[order.id]['amount_untaxed'] = cur_obj.round(cr,uid,cur,val1)
            res[order.id]['amount_total'] = res[order.id]['amount_tax'] + res[order.id]['amount_untaxed'] 
     
    def _amount_line_tax(self, cr, uid, line, context=None): 
         val = 0.0 
         for c in self.pool.get('account.tax').compute_all(cr,uid,line.tax_id,line.price_unit*(1-(line.discount or 0.0)/100.0),line.product_uom_qty,line.product_id,line.order_id.partner_id)['taxes']:
             val += c.get('amount',0.0)
         return val  
    
    def _get_order(self,cr,uid,ids,context=None):
        result = {}
#         for line in self.pool.get('sale.order.line').browse(cr,uid,ids,context=context):
#             result[line.order_id.id] = True
        return result.keys()
    
    def _get_default_company(self, cr, uid, context=None):
        company_id = self.pool.get('res.users')._get_company(cr, uid, context=context)
        if not company_id:
            raise osv.except_osv(_(u'错误！'),_(u'当前用户没有默认公司！'))
        return company_id
    
    def _get_default_section_id(self, cr, uid, context=None):
        """ 通过检查上下文中出现的参数，给出一个默认的销售团队"""
        section_id = self._resolve_section_id_from_context(cr, uid, context=context) or False
        if not section_id:
            section_id = self.pool.get('res.users').browse(cr, uid, uid, context).default_section_id.id or False
        return section_id
    
    def _resolve_section_id_from_context(self, cr, uid, context=None):
        """ 根据关键字'section_id'上下文的值返回销售团队，如果不是 一个单独的销售团队，则不返回 """
        if context is None:
            context={}
        if tpye(context.get('default_section_id')) in (int,long):
            return context.get('default_section_id')
        if isinstance(context.get('default_section_id'),basestring):
            section_ids = self.pool.get('crm.case.section').name_search(cr, uid, name=context['default_section_id'],context=context)
            if len(section_ids)==1:
                return int(section_ids[0][0])
        return None

    _columns = {
        'name':fields.char(u'订单编号',required=True ,copy=False, readonly=True, states={'draft':[('readonly',False)], 'sent':[('readonly',False)]},select=True),
        'origin':fields.char(u'源单据',help=u"生成该销售订单请求的参考文档"),
        'client_order_ref':fields.char(u'参考/描述',copy=False),
        'state':fields.selection([
            ('draft', u'报价单草稿'),
            ('sent', u'报价单已发送'),
            ('cancel', u' 取消'),
            ('waiting_date', u' 等待调度'),
            ('progress', u' 销售订单'),
            ('manual', u' 待开票'),
            ('shipping_except',u'发货异常'),
            ('invoice_except',u' 发票异常'),
            ('done', u'完成'),
        ], u'状态', readonly=True, copy=False, help='报价单或者销售订单的状态\
            \n异常状态是在发票被取消（发票异常）或发货单被取消（发货异常）时自动设置的 \
            \n等待调度的状态当发票被确认但等待调度在订单日运行',select=True),  
        'date_order':fields.datetime(u'日期', required=True, readonly=True, select=True,states={'draft':[('readonly',False)],'sent':[('readonly',False)]},copy=False),
        'create_date':fields.datetime(u'创建日期', readonly=True, select=True, help=u"订单创建日期"), 
        'date_confirm':fields.date(u'确认日期', readonly=True, select=True, help=u"订单确认日期", copy=False),
        'user_id':fields.many2one('res.users', u'销售人员', states={'draft':[('readonly',False)],'sent':[('readonly',False)]},select=True,track_visibility='onchange'),
        'partner_id':fields.many2one('res.partner', u'客户', readonly=True, states={'draft':[('readonly',False)],'sent':[('readonly',False)]}, required=True, change_default=True, select=True,track_visibility='always'),
        'partner_invoice_id':fields.many2one('res.partner', u'发票地址', readonly=True, required=True,states={'draft':[('readonly',False)],'sent':[('readonly',False)]}, help=u"当前销售订单的发票地址"),
        'partner_shipping_id':fields.many2one('res.partner', u'发货地址', readonly=True, required=True, states={'draft':[('readonly',False)],'sent':[('readonly',False)]}, help=u"当前订单的发货地址"),
        'order_policy':fields.selection([('manual', u'按需开票')], u'结算方式', required=True, readonly=True, states={'draft':[('readonly',False)],'sent':[('readonly',False)]}, help=u"""该字段控制开发票和发货的顺序"""),
        'pricelist_id':fields.many2one('product.pricelist', u'价格表', required=True, readonly=True, states={'draft':[('readonly',False)],'sent':[('readonly',False)]}, help=u"当前销售订单的价格表"),
        'currency_id':fields.related('pricelist_id', 'currency_id', type="many2one", relation="res.currency", string="货币",readonly=True, required=True),
        'project_id':fields.many2one('account.analytic.account', u'合同/分析', readonly=True, states={'draft':[('readonly',False)],'sent':[('readonly',False)]}, help=u"销售订单相关的账目协议"),

        #'order_line':fields.one2many('sale.order.line', 'order_id', u'订单行', readonly=True, states={'draft':[('readonly',False)],'sent':[('readonly',False)]}, copy=True),
        'invoice_ids':fields.many2many('account.invoice', 'sale_order_invoice_rel', 'order_id', 'invoice_id', u'发票', readonly=True, copy=False, help=u"已生成的销售订单的发票列表，同一销售订单可能分几次开发票（比如通过行表添加）"),
        'invoiced_rate':fields.function(_invoiced_rate, string=u'发票比率', type='float'),
        'invoiced':fields.function(_invoiced, string=u'该订单所有发票已支付', fnct_search=_invoiced_search, type='boolean', help=u"表明该订单所有发票已支付"),
        'invoice_exists':fields.function(_invoice_exists, string=u'已开发票', fnct_search=_invoiced_search, type='boolean', help=u"表明该销售订单至少有一个发票"),
        'note':fields.text(u'条款和条件'),
        'amount_untaxed':fields.function(_amount_all_wrapper, digits_compute=dp.get_precision('Account'), string=u'不含税金额', 
                store={
                    'sale.order':(lambda self ,cr, uid, ids, c={}:ids, ['order_line'], 10 ),
                    #'sale.order.line':(_get_order, ['price_unit','tax_id','discount','product_uom_qty'], 10), 
                 },
                 multi='sums', help="不含税金额",track_visibility='always',),
        'amount_tax':fields.function(_amount_all_wrapper, digits_compute=dp.get_precision('Account'), string=u'税',
                store={
                    'sale.order':(lambda self ,cr, uid, ids, c={}:ids, ['order_line'], 10 ),
                    #'sale.order.line':(_get_order, ['price_unit','tax_id','discount','product_uom_qty'], 10), 
                 },
                 multi='sums', help="税额"),
        'amount_total':fields.function(_amount_all_wrapper,digits_compute=dp.get_precision('Account'), string=u'合计', 
                store={
                    'sale.order':(lambda self ,cr, uid, ids, c={}:ids, ['order_line'], 10 ),
                    #'sale.order.line':(_get_order, ['price_unit','tax_id','discount','product_uom_qty'], 10), 
                 },
                 multi='sums', help="总金额",),
        'payment_term':fields.many2one('account.payment.term', u'付款期限',),
        'fiscal_position':fields.many2one('account.fiscal.position',u'替换规则'),
        'company_id':fields.many2one('res.company', u'公司'),
        'section_id':fields.many2one('crm.case.section', u'销售团队'),
        'procurement_group_id':fields.many2one('procurement.group', u'采购组', copy=False),
        'product_id':fields.related('order_line', 'product_id', type='many2one', relation='product.product', string=u'产品'),
    }
    
    _defaults = {
        'date_order': fields.datetime.now,
        'order_policy': 'manual',
        'company_id': _get_default_company,
        'state': 'draft',
        'user_id': lambda obj, cr, uid, context: uid,
        'name': lambda obj, cr, uid, context: '/',
        'partner_invoice_id': lambda self, cr, uid, context: context.get('partner_id', False) and self.pool.get('res.partner').address_get(cr, uid, [context['partner_id']], ['invoice'])['invoice'],
        'partner_shipping_id': lambda self, cr, uid, context: context.get('partner_id', False) and self.pool.get('res.partner').address_get(cr, uid, [context['partner_id']], ['delivery'])['delivery'],
        'note': lambda self, cr, uid, context: self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.sale_note,
        'section_id': lambda s, cr, uid, c: s._get_default_section_id(cr, uid, c),
    }
    _sql_constraints = [
        ('name_uniq', 'unique(name, company_id)', u'每个公司的订单编号必须唯一!'),
    ]
    _order = 'date_order desc, id desc'
    
    def onchange_pricelist_id(self, cr, uid, ids, pricelist_id, order_lines, context=None):
        context = context or {}
        if not pricelist_id:
            return {}
        value = {
            'currency_id': self.pool.get('product.pricelist').browse(cr, uid, pricelist_id, context=context).currency_id.id
        }
        if not order_lines or order_lines == [(6, 0, [])]:
            return {'value': value}
        warning = {
            'title': _('Pricelist Warning!'),
            'message' : _('If you change the pricelist of this order (and eventually the currency), prices of existing order lines will not be updated.')
        }
        return {'warning': warning, 'value': value}
        
    def onchange_delivery_id(self, cr, uid, ids, company_id, partner_id, delivery_id, fiscal_position, context=None):
        r = {'value': {}}
        if not fiscal_position:
            if not company_id:
                company_id = self._get_default_company(cr, uid, context=context)
            fiscal_position = self.pool['account.fiscal.position'].get_fiscal_position(cr, uid, company_id, partner_id, delivery_id, context=context)
            if fiscal_position:
                r['value']['fiscal_position'] = fiscal_position
        return r
    
